package hallows;
import java.util.Map;

import com.hp.hpl.jena.query.DatasetFactory
import com.hp.hpl.jena.rdf.model.ModelFactory
import com.hp.hpl.jena.ontology.OntModel
import com.hp.hpl.jena.sparql.core.DataSourceImpl
import com.hp.hpl.jena.query.QueryExecutionFactory
import com.hp.hpl.jena.query.QueryExecution
import com.hp.hpl.jena.rdf.model.Resource
import com.hp.hpl.jena.rdf.model.Property
import com.hp.hpl.jena.rdf.model.Literal
import com.hp.hpl.jena.ontology.OntClass
import com.hp.hpl.jena.rdf.model.Statement
import com.hp.hpl.jena.ontology.ObjectProperty
import com.hp.hpl.jena.ontology.DatatypeProperty

public class DataStore {
	DataSourceImpl datasource= null
	OntModel model= null
	
	// set up the model, load it with the provided ontology,
	// and add it to the datasource
	def Dataset(File owl) {
		model= ModelFactory.createOntologyModel()
		model.read(new FileInputStream(owl), "http://www.hallows.com/registry", "TTL")
		datasource= DatasetFactory.create(model)
		datasource.setDefaultModel(model)
	}
	
	// check to make sure that the service isn't already in the system
	// then break down the Map and add it to the default model
	def addWebService(Map<String, Object> serviceContents) {
		model= model.begin()
		def wsString= serviceContents['service']
		Resource ws= model.createResource(wsString)
		Property isa= model.getProperty('http://rdf.com', 'type')
		Property hasOperation= model.getProperty('http://www.hallows.com', 'hasOperation')
		OntClass WebService= model.getOntClass('http://www.hallows.com/WebService')
		OntClass Operation= model.getOntClass('http://www.hallows.com/Operation')
		Statement isaWS= model.createStatement(ws, isa, WebService)
		if (model.contains(isaWS)) {
			model= model.abort()
			return ['status':'Error: web service already exists']
		}
		else {
			model.add(isaWS)
			serviceContents['operations'].each { op ->
				Resource operation= model.createResource("http://www.hallows.com/${op}")
				Statement isaOp= model.createStatement(operation, isa, Operation)
				Statement hasOp= model.createStatement(ws, hasOperation, operation)
				model= model.add(isaOp).add(hasOp)
			}
			model= model.commit()
			return ['status':'ok']
		}
		
	}
	// if a web service is in the catalog, then
	// get all of its operations and messages
	// remove all facts related to the web service, its operations, and its messages
	def removeWebService(String serviceUrl) {
		model= model.begin()
		Resource ws= model.getResource(serviceUrl)
		Property isa= model.getProperty('http://rdf.com', 'type')
		OntClass WebService= model.getOntClass('http://www.hallows.com/WebService')
		Statement isaWS= model.createStatement(ws, isa, WebService)
		if (model.contains(isaWS)) {
			def queryString= """
			Construct { ?s ?p ?o }
			Where {
				{ ?s rdf:type hallows:WebService .
				  Filter (?s = ${ws}) }
				union
				{ ${ws} hallows:hasOperation ?s }
				union 
				{ ${ws} hallows:hasOperation/hallows:hasMessage ?s }
				.
				{ ?s ?p ?o }
				union
				{ ?o ?p ?s }
			}
			"""
			model= model.remove(QueryExecutionFactory.create(queryString, model).execConstruct().listStatements())
			return ['status':'ok']
		}
		else { return ['status':'Error: web service not found'] }
	}
	
	// add a fact to the model, silently aborting if the 
	// fact is already there
	def addFact(String s, String p, Object o) {
		model.begin()
		Statement fact= createFact(s, p, o)
		if (model.contains(fact)) {
			model= model.abort()
			return ['status':'ok']
		}
		else {
			model= model.add(fact).commit()
			return ['status':'ok']
		}
	}
	
	// remove a fact from the model, silently aborting if the 
	// fact is not there
	def removeFact(String s, String p, Object o) {
		model.begin()
		Statement fact= createFact(s, p, o)
		if (model.contains(fact)) {
			model= model.remove(fact).commit()
			return ['status':'ok']
		}
		else {
			model.abort()
			return ['status':'ok']
		}
	}
	
	def removeFacts(String s, String p) {
		model.begin()
		String subject= model.getResource(s).toString()
		String property= model.getProperty(p).toString()
		String query= "Construct {$s $p ?o} Where {$s $p ?o}"
		model= model.remove(QueryExecutionFactory.create(query, model).execConstruct().listStatements()).commit()
		return ['status':'ok']
	}

	
	
	// Create a statement, using a
	// resource in the 'object' position if an ObjectProperty is used,
	// literal in the 'object' position if a DatatypeProperty is used,
	// and a resource in the 'object' position if just a regular Property is used
	def createFact(String s, String p, Object o) {
		Resource subject= model.getResource(s)
		if (model.getObjectProperty(p)) {
			ObjectProperty predicate= model.getObjectProperty(p)
			try {
				Resource object= model.createResource(new URL(o))
			}
			catch (MalformedURLException e) {
				return ['status':'Error: ObjectProperty detected, but object is an invalid url']
			}
		}
		else if (model.getDatatypeProperty(p)) {
			DatatypeProperty predicate= model.getDatatypeProperty(p)
			Literal object= model.createLiteral(o)
		}
		else {
			Property predicate= model.getProperty(p)
			Resource object= model.createResource(o)
		}
		return model.createStatement(s, p, o)
	}
	
	def addRdfFacts(String messageUrl, String rdfString) {
		model.begin()
		Resource subject= model.getResource(messageUrl)
		OntModel payload= ModelFactory.createOntologyModel()
		model.read(rdfString, "TTL")
	}
}
